手写数字识别(二) 您所在的位置:网站首页 matlab datamat 手写数字识别(二)

手写数字识别(二)

2023-08-07 11:07| 来源: 网络整理| 查看: 265

前言

前两天利用kNN实现了手写数字的识别,数据不是很多,训练数据1934个,测试数据946个。

这两天把Mnist-image的手写数字数据down了下来,利用SVM进行识别一下。

Mnist-image的手写数字数据有7万的图像数据(6万训练数据+1万测试数据),每个图像数据为 20px * 20px。

数据长啥样?

手写字体0的数据

上面是手写数字‘0’的图像数据的一部分。

0_1.png

这是0_1.png放大的效果,20px * 20px。

怎么搞?

有了数据,我们怎么搞呢?

1.把图像数据转换成向量

用numpy向量来表示图像数据。 首先将图像数据灰度化处理,然后将其存入在numpy数组中,此时每一个元素的取值范围为0~255。接着,我们对其进行灰度变换,将其映射到0~1的范围内,并对每个元素四舍五入,让取值为0或者1,最终化为二值矩阵。最后把20 * 20的二值矩阵转换为1 * 400的向量。

# 将 20px * 20px 的图像数据转换成 1*400 的 numpy 向量 # 参数:imgFile--图像名 如:0_1.png # 返回:1*400 的 numpy 向量 def img2vector(imgFile): img = Image.open(imgFile).convert('L') img_arr = np.array(img, 'i') # 20px * 20px 灰度图像 img_normlization = np.round(img_arr/255) # 对灰度值进行归一化 img_arr2 = np.reshape(img_normlization, (1,-1)) # 1 * 400 矩阵 return img_arr2 2. 读取每个数字的所有实例,转换为矩阵

接着我们需要把每个数字的所有实例都转换成1 * 400的向量,并将它们转换成N * 400(N为实例数量)的矩阵。

# 读取一个类别的所有数据并转换成矩阵 # 参数: # basePath: 图像数据所在的基本路径 # Mnist-image/train/ # Mnist-image/test/ # cla:类别名称 # 0,1,2,...,9 # 返回:某一类别的所有数据----[样本数量*(图像宽x图像高)] 矩阵和标签向量 def read_and_convert(imgFileList): dataLabel = [] # 存放类标签 dataNum = len(imgFileList) dataMat = np.zeros((dataNum, 400)) # dataNum * 400 的矩阵 for i in range(dataNum): imgNameStr = imgFileList[i] imgName = get_img_name_str(imgNameStr) # 得到 数字_实例编号.png #print("imgName: {}".format(imgName)) classTag = imgName.split(".")[0].split("_")[0] # 得到 类标签(数字) #print("classTag: {}".format(classTag)) dataLabel.append(classTag) dataMat[i,:] = img2vector(imgNameStr) return dataMat, dataLabel 3. 整合训练数据

读取所有数字的所有实例,整合成一个60000 * 400的超大矩阵(呵呵,其实没多大)。

# 读取训练数据 def read_all_data(): cName = ['1', '2', '3', '4', '5', '6', '7', '8', '9'] train_data_path = "Mnist-image\\train\\0" flist = get_file_list(train_data_path) dataMat, dataLabel = read_and_convert(flist) for c in cName: train_data_path_ = "Mnist-image\\train\\" + c flist_ = get_file_list(train_data_path_) dataMat_, dataLabel_ = read_and_convert(flist_) dataMat = np.concatenate((dataMat, dataMat_), axis=0) dataLabel = np.concatenate((dataLabel, dataLabel_), axis=0) print(dataMat.shape) print(len(dataLabel)) return dataMat, dataLabel

此时我们的训练数据就准备好了。

加载数据后,我们看看这个矩阵:

训练数据矩阵

上面的array是60000 * 400的训练数据,下面的array是1 * 60000的类标签数据。

4. 构造SVM模型

SVM既可以用来处理分类问题,也可以用来作回归任务。SVM不修改的话,只能用来进行处理二分类问题。

手写数字字体识别,显然是个多类别分类问题。对于多分类问题,解决的基本思路是“拆分法”,即将多个二分类问题拆分为若干个十分类任务进行求解。具体来讲,先对问题进行拆分,然后为拆出的每个十分类任务训练一个分类器,在测试时,对这些二分类器的结果进行集成以获得最终的多分类结果。拆分的策略主要有以下几种:

OvO(one-vs-one) 这种解决方法的思路是:对于有N个类别的分类任任务,将这N个类别两两配对,从而产生N(N-1)/2个二分类任务。在测试阶段,新样本同时提交给所有分类器,这样可以得到N(N-1)/2个分类结果,最终的结果可以通过投票产生:即把预测的最多的类别作为最终的分类结果。OvR(one-vs-rest) 这种解决方法的思路是:每次将一个类的样例作为正例,所有其他类的样例作为负例来训练N个分类器。在测试时,若仅有一个分类器预测为正类,则对应的类别标记为最终分类结果。

两种策略对比:

明显看出,OvR只需要训练N个分类器,而OvO需要训练N(N-1)/2个分类器,因此OvO的存储开销和测试时间开销通常比OvR更大。但在训练时,OvR的每个分类器均使用全部训练样例,而OvO的每个分类器仅用到两个类的样例。因此,在类别很多的时候,OvO的训练时间开销通常比OvR更小。至于性能,取决于具体的数据分布,多数情况下两者差不多。

# create model def create_svm(dataMat, dataLabel, decision='ovr'): clf = svm.SVC(decision_function_shape=decision) clf.fit(dataMat, dataLabel) return clf

SVC参数:

SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0, decision_function_shape='ovr', degree=3, gamma='auto', kernel='rbf', max_iter=-1, probability=False, random_state=None, shrinking=True, tol=0.001, verbose=False) 5. 分类测试

读取测试数据,整合成矩阵

# 对10个数字进行分类测试 def main(): tbasePath = "Mnist-image\\test\\" tcName = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] tst = time.clock() allErrCount = 0 allErrorRate = 0.0 allScore = 0.0 for tcn in tcName: testPath = "Mnist-image\\test\\" + tcn #print("class " + tcn + " path is: {}.".format(testPath)) tflist = get_file_list(testPath) #tflist tdataMat, tdataLabel = read_and_convert(tflist) print("test dataMat shape: {0}, test dataLabel len: {1} ".format(tdataMat.shape, len(tdataLabel))) #print("test dataLabel: {}".format(len(tdataLabel))) pre_st = time.clock() preResult = clf.predict(tdataMat) pre_et = time.clock() print("Recognition " + tcn + " spent {:.4f}s.".format((pre_et-pre_st))) #print("predict result: {}".format(len(preResult))) errCount = len([x for x in preResult if x!=tcn]) print("errorCount: {}.".format(errCount)) allErrCount += errCount score_st = time.clock() score = clf.score(tdataMat, tdataLabel) score_et = time.clock() print("computing score spent {:.6f}s.".format(score_et-score_st)) allScore += score print("score: {:.6f}.".format(score)) print("error rate is {:.6f}.".format((1-score))) print("---------------------------------------------------------") tet = time.clock() print("Testing All class total spent {:.6f}s.".format(tet-tst)) print("All error Count is: {}.".format(allErrCount)) avgAccuracy = allScore/10.0 print("Average accuracy is: {:.6f}.".format(avgAccuracy)) print("Average error rate is: {:.6f}.".format(1-avgScore))

分类结果:

test dataMat shape: (980, 400), test dataLabel len: 980 Recognition 0 spent 9.5305s. errorCount: 11. computing score spent 9.693493s. score: 0.988776. error rate is 0.011224. --------------------------------------------------------- test dataMat shape: (1135, 400), test dataLabel len: 1135 Recognition 1 spent 10.7278s. errorCount: 11. computing score spent 10.832672s. score: 0.990308. error rate is 0.009692. --------------------------------------------------------- test dataMat shape: (1032, 400), test dataLabel len: 1032 Recognition 2 spent 9.7781s. errorCount: 57. computing score spent 9.973572s. score: 0.944767. error rate is 0.055233. --------------------------------------------------------- test dataMat shape: (1010, 400), test dataLabel len: 1010 Recognition 3 spent 9.6072s. errorCount: 55. computing score spent 10.072705s. score: 0.945545. error rate is 0.054455. --------------------------------------------------------- test dataMat shape: (982, 400), test dataLabel len: 982 Recognition 4 spent 9.4975s. errorCount: 44. computing score spent 9.271692s. score: 0.955193. error rate is 0.044807. --------------------------------------------------------- test dataMat shape: (892, 400), test dataLabel len: 892 Recognition 5 spent 8.4760s. errorCount: 70. computing score spent 8.578377s. score: 0.921525. error rate is 0.078475. --------------------------------------------------------- test dataMat shape: (958, 400), test dataLabel len: 958 Recognition 6 spent 9.0267s. errorCount: 27. computing score spent 9.043633s. score: 0.971816. error rate is 0.028184. --------------------------------------------------------- test dataMat shape: (1028, 400), test dataLabel len: 1028 Recognition 7 spent 9.8431s. errorCount: 66. computing score spent 9.765103s. score: 0.935798. error rate is 0.064202. --------------------------------------------------------- test dataMat shape: (974, 400), test dataLabel len: 974 Recognition 8 spent 9.3546s. errorCount: 75. computing score spent 9.849029s. score: 0.922998. error rate is 0.077002. --------------------------------------------------------- test dataMat shape: (1009, 400), test dataLabel len: 1009 Recognition 9 spent 9.6555s. errorCount: 79. computing score spent 9.595665s. score: 0.921705. error rate is 0.078295. --------------------------------------------------------- Testing All class total spent 196.587770s. All error Count is: 495. Average accuracy is: 0.949843. Average error rate is: 0.050157. 6. 结果分析

从以上结果可以看出,SVM对于手写数字字体识别的准确率还是相对较高的,94.9%。在本例中,对灰度值归一化的时候,截取了小数点后一位,对并其四舍五入,归一化为0或1,得到0-1的二值矩阵。如果采取不同的处理方式,得到不同的二值矩阵,即不同的特征矩阵,则分类结果会不相同。

后续

本篇文章简要介绍了利用机器学习中的SVM模型对手写数字字体识别,手写数字字体数据集是Mnist-image。下篇我们将利用深度学习框架TensorFlow来构建神经网络对该数据集进行识别。

参考 《机器学习》,周志华《Python计算机视觉编程》,Jan Erik SolemMnist-image 数据,点击这里TensorFlow, 点击这里

Standing on Shoulders of Giants.



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有